package main

import (
	"fmt"
	"log"
	"regexp"
	"strings"
)

/*
Golang正则基本语法说明
 regexp.MustCompile是最左、最短匹配，
 regexp.MustCompilePOSIX是最左、最长匹配
(?U) 表示非贪婪匹配
(?i) 忽略大小写
*/

// ReToSingleSpace 处理换行和空格
/*
1、CREATE语句中第一个(后加换行
2、CREATE语句中第一个(后多个换行变一个
3、连续三个换行换成2个
4、特殊符号后的多行换行边单行 目前: ( )
5、多个空格或者制表符换成空格*/
func ReToSingleSpace(srcString *string) *string {

	*srcString = strings.Replace(*srcString, "\"", "", -1) // 去掉双引号

	re := regexp.MustCompile("\\) *WITH")
	*srcString = re.ReplaceAllString(*srcString, ")\nWITH")

	re = regexp.MustCompile(" *, *")
	*srcString = re.ReplaceAllString(*srcString, ",")

	re = regexp.MustCompile("(?iU)character +varying")
	*srcString = re.ReplaceAllString(*srcString, "VARCHAR")

	re = regexp.MustCompile("(?U)(CREATE)(.|[\n])*\\(")
	for _, oldValue := range re.FindAllString(*srcString, -1) {
		*srcString = strings.Replace(*srcString, oldValue, oldValue+"\n", -1) // 把包裹字段的括号，前部分 ( 加上一个换行
	}
	re = regexp.MustCompile("(?U)(CREATE).*(\n){2,}.*\\(") // （?U）表示非贪婪匹配
	for _, oldValue := range re.FindAllString(*srcString, -1) {
		reTmp := regexp.MustCompile("(\n){2,}")
		newValue := reTmp.ReplaceAllString(oldValue, "\n") // 把包裹字段的括号，前部分 ( 后多个换行变成一个换行
		*srcString = strings.Replace(*srcString, oldValue, newValue, -1)
	}

	re = regexp.MustCompile("((\n)[ ]*){3,}") // 连续三个换行换成2个
	*srcString = re.ReplaceAllString(*srcString, "\n\n")

	for _, value := range []string{"\\(", "\\)"} {
		//reC := "([" + value + "])((\n)[ ]*){2,}"
		reC := fmt.Sprintf("([%s])((\n)[ ]*){2,}", value)
		re = regexp.MustCompile(reC)                                                                            // 特殊符号后的 多行换行边单行
		*srcString = re.ReplaceAllString(*srcString, fmt.Sprintf("%s\n", strings.Replace(value, "\\", "", -1))) // 这里去掉转译斜杠
	}

	re = regexp.MustCompile("[ \\t]+") // 多个空格或者制表符换成空格
	*srcString = re.ReplaceAllString(*srcString, " ")

	return srcString
}

// ReDelSpecificSpace 删除一些特定的空格 ( 后的 ) 前  :: 前后中间
func ReDelSpecificSpace(srcString *string) *string {
	re := regexp.MustCompile("\\( +| +\\)|::( )+|( )+::|: +:")
	for len(re.FindAllString(*srcString, -1)) > 0 {
		for _, oldValue := range re.FindAllString(*srcString, -1) {
			newValue := strings.Replace(oldValue, " ", "", -1)
			*srcString = strings.Replace(*srcString, oldValue, newValue, -1)
		}
	}
	return srcString
}

// ReKeyWordToUpper 关键字大写
func ReKeyWordToUpper(srcString *string, keyWords *[]string) *string {
	for _, keyWord := range *keyWords {
		keyWord = strings.ToUpper(keyWord)                 // 关键字大写
		reComStr1 := "(?iU)" + "[^.]+" + keyWord + "[^.]+" // 忽略大小写  关键字前不能有英文字母或者下划线
		reComStr2 := "(?iU)" + "^" + keyWord + "[^.]+"     // 忽略大小写  关键字可能出现在最开始
		re := regexp.MustCompile(reComStr1 + "|" + reComStr2)

		for index, oldValue := range re.FindAllString(*srcString, -1) {
			log.Printf("keyWord=%s index= %d oldValue++++++>%s", keyWord, index, oldValue)
			reW := regexp.MustCompile("(?i)" + keyWord)
			newValue := reW.ReplaceAllString(oldValue, keyWord)
			*srcString = strings.Replace(*srcString, oldValue, newValue, -1)
		}
	}
	return srcString
}

// InfoCreateSQL 获取 CreateSQL语句信息
type InfoCreateSQL struct {
	sqlID   int
	rowID   int
	SQLInfo string
	detInfo []string // 按照空格切分后的信息
}

// CreateSQLToFormat Create语句格式化处理
func CreateSQLToFormat(srcString *string) *string {

	re := regexp.MustCompile("(?U)(CREATE)(.|[\n])*\\)( |[\n])*WITH") // CREATE 开始 任意字符 中间  WITH 结束
	createList := re.FindAllString(*srcString, -1)

	infoCreateSQL := make(map[int]([]InfoCreateSQL)) // 每一行SQL信息
	lenInfo := make(map[int](map[int]int))           // 每段SQL，按行统计每列最长长度
	wishToReplace := make(map[int]string)

	for createIndex, createSQL := range createList {
		re = regexp.MustCompile("((?U)(CREATE)(.|[\n])*\\()|(\\)( |[\n])*WITH)") // 把CRETE和WITH部分去掉只调整字段对齐
		createSQL = re.ReplaceAllString(createSQL, "")
		wishToReplace[createIndex] = createSQL
		colMaxLen := make(map[int]int)
		var infoOneCreateSQL []InfoCreateSQL
		for rowIndex, rowValue := range strings.Split(createSQL, "\n") {

			rowValue = DeletePreAndSufSpace(rowValue) // 去除前后空格

			re := regexp.MustCompile("--.*") // CREATE 开始 任意字符 中间  WITH 结束
			commentInfo := re.FindAllString(rowValue, -1)
			rowValue = re.ReplaceAllString(rowValue, "")                         // 我们把注释去掉
			everyRowList := append(strings.Split(rowValue, " "), commentInfo...) // 每行的信息我们分成注释部分和正常部分，正常部分按照空格切分，注释整体作为最后一个元素

			// 不要空的数据
			if len(everyRowList) == 1 && everyRowList[0] == "" {
				continue
			}
			for index, value := range everyRowList {
				tmpLen := len(string([]rune(value))) + 1
				re = regexp.MustCompile("--.*")
				if re.MatchString(value) {
					tmpLen = 0
				}

				if col, ok := colMaxLen[index]; ok {
					if col < tmpLen {
						colMaxLen[index] = tmpLen
					}
				} else {
					colMaxLen[index] = tmpLen
				}
			}
			infoOneCreateSQL = append(infoOneCreateSQL, InfoCreateSQL{sqlID: createIndex, rowID: rowIndex, detInfo: everyRowList})
		}
		infoCreateSQL[createIndex] = infoOneCreateSQL
		lenInfo[createIndex] = colMaxLen
	}
	//newSQLForWish := make(map[int]string)
	for sqlID, sqlInfo := range infoCreateSQL {
		totalLength := 0 // 记录每行除了注释期待总长度
		for _, tmpLen := range lenInfo[sqlID] {
			totalLength += tmpLen
		}
		newSQLForWish := "\n"
		for _, colInfo := range sqlInfo {
			tmpSumLen := 0
			newSQLForWish += "  " // 每行字段前加两个空格
			for index, value := range colInfo.detInfo {
				//log.Printf("value++++++>%s<++++++", value)
				wishLen := (lenInfo[sqlID])[index]
				re = regexp.MustCompile("--.*")
				if re.MatchString(value) {
					newSQLForWish += AddSpaceToPre(value, totalLength-tmpSumLen+1)
				} else {
					newSQLForWish += AddSpaceToSuf(value, wishLen)
				}
				tmpSumLen += wishLen
			}
			newSQLForWish += "\n"
		}
		// log.Printf("newSQLForWish***>%s", newSQLForWish)
		*srcString = strings.Replace(*srcString, wishToReplace[sqlID], newSQLForWish, -1)
	}

	return srcString
}

// AddSpaceToSuf 给字符串结尾补充空格到指定长度
func AddSpaceToSuf(srcString string, wishLen int) string {
	srcLen := len(string([]rune(srcString)))
	for wishLen > srcLen {
		srcString += " "
		srcLen++
	}
	return srcString
}

// AddSpaceToPre 给字符串前缀补充空格到指定长度
func AddSpaceToPre(srcString string, wishLen int) string {
	srcLen := 0
	for wishLen > srcLen {
		srcString = " " + srcString
		srcLen++
	}
	return srcString
}

// DeletePreAndSufSpace 删除字符串前后的空格
func DeletePreAndSufSpace(str string) string {
	tmpString := strings.TrimLeft(str, " ")
	tmpString = strings.TrimRight(tmpString, " ")
	return tmpString
}
